﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using YinfangWeb.MLog;

namespace YinfangWeb.Common
{
    public class FtpHelper
    {
        public string HostName
        {
            get; set;
        }

        public string UserName
        {
            get; set;
        }

        public string Password
        {
            get; set;
        }

        public FtpHelper()
        {
        }

        public bool CreateDir(string targetDir)
        {
            if (!_CheckedConfig())
            {
                throw new InvalidOperationException("ftp 服务器配置验证失败");
            }
            if (string.IsNullOrWhiteSpace(targetDir))
            {
                return false;
            }
            var ftpDirPath = $"ftp://{HostName}/{targetDir}/";
            //判断 ftp 服务器上是否有该文件夹，没有就创建
            if (!_DirectoryExists(ftpDirPath))
            {
                return _CreateDirectory(ftpDirPath);
            }
            return true;
        }
        public string UploadSpFile(string target, byte[] fileContent, string targetDir)
        {
            if (!_CheckedConfig())
            {
                throw new InvalidOperationException("ftp 服务器配置验证失败");
            }
            if (string.IsNullOrWhiteSpace(targetDir) || string.IsNullOrWhiteSpace(target) || fileContent.Length <= 0)
            {
                return string.Empty;
            }
            var ftpDirPath = $"ftp://{HostName}/{targetDir}/";
            //判断 ftp 服务器上是否有该文件夹，没有就创建
            if (!_DirectoryExists(ftpDirPath))
            {
                _CreateDirectory(ftpDirPath);
            }
            
            string URI = $"{ftpDirPath}{target}";

            using (WebClient client = new WebClient())
            {
                client.Credentials = new NetworkCredential(UserName, Password);
                client.UploadData(URI, "STOR", fileContent);
            }
            return target;
        }

        public string UploadFile(string fileName, byte[] fileContent, string targetDir)
        {
            if (!_CheckedConfig())
            {
                throw new InvalidOperationException("ftp 服务器配置验证失败");
            }
            if (string.IsNullOrWhiteSpace(targetDir) || string.IsNullOrWhiteSpace(fileName) || fileContent.Length <= 0)
            {
                return string.Empty;
            }
            var ftpDirPath = $"ftp://{HostName}/{targetDir}/";
            //判断 ftp 服务器上是否有该文件夹，没有就创建
            if (!_DirectoryExists(ftpDirPath))
            {
                _CreateDirectory(ftpDirPath);
            }
            var dotIndex = fileName.LastIndexOf(".");
            if (dotIndex <= 0)
            {
                return string.Empty;
            }
            var ext = fileName.Substring(dotIndex);
            var target = Guid.NewGuid().ToString("N") + ext;  //使用临时文件名

            string URI = $"{ftpDirPath}{target}";

            using (WebClient client = new WebClient())
            {
                client.Credentials = new NetworkCredential(UserName, Password);
                client.UploadData(URI, "STOR", fileContent);
            }
            return target;
        }

        public bool Rename(string source, string destination)
        {
            if (!_CheckedConfig())
            {
                throw new InvalidOperationException("ftp 服务器配置验证失败");
            }
            if (source == destination)
                return false;

            Uri uriSource = new Uri("ftp://" + HostName + "/" + source, UriKind.Absolute);
            Uri uriDestination = new Uri("ftp://" + HostName + "/" + destination, UriKind.Absolute);

            // 源文件是否存在，不存在报异常
            if (!_FileExists(uriSource.AbsoluteUri))
            {
                throw (new FileNotFoundException(string.Format("Source '{0}' not found!", uriSource.AbsolutePath)));
            }

            //目标文件是否存在，存在报异常
            if (_FileExists(uriDestination.AbsoluteUri))
            {
                throw (new ApplicationException(string.Format("Target '{0}' already exists!", uriDestination.AbsolutePath)));
            }

            var targetDir = destination.Split('/')[0];
            var ftpDirPath = $"ftp://{HostName}/{targetDir}/";
            //判断 ftp 服务器上是否有该文件夹，没有就创建
            if (!_DirectoryExists(ftpDirPath))
            {
                _CreateDirectory(ftpDirPath);
            }

            Uri targetUriRelative = uriSource.MakeRelativeUri(uriDestination);

            //perform rename
            try
            {
                FtpWebRequest ftp = _GetRequest(uriSource.AbsoluteUri);
                ftp.Method = WebRequestMethods.Ftp.Rename;
                ftp.RenameTo = Uri.UnescapeDataString(targetUriRelative.OriginalString);

                FtpWebResponse response = (FtpWebResponse)ftp.GetResponse();
                return true;
            }
            catch (Exception ex)
            {
                Logger.Default.Warn("FTP 服务器重命名文件失败，源文件路径：" + source, ex);
                throw ex;
            }
        }

        public bool DeleteFile(string source)
        {
            if (!_CheckedConfig())
            {
                throw new InvalidOperationException("ftp 服务器配置验证失败");
            }
            Uri uriSource = new Uri("ftp://" + HostName + "/" + source, UriKind.Absolute);
            if (!_FileExists(uriSource.AbsoluteUri))
            {
                throw (new FileNotFoundException(string.Format("Source '{0}' not found!", uriSource.AbsolutePath)));
            }
            return _FileDelete(uriSource.AbsoluteUri);
        }

        private bool _CheckedConfig()
        {
            if (string.IsNullOrEmpty(HostName) || string.IsNullOrEmpty(UserName) || string.IsNullOrEmpty(Password))
            {
                return false;
            }
            return true;
        }

        private FtpWebRequest _GetRequest(string URI)
        {
            //根据服务器信息FtpWebRequest创建类的对象
            FtpWebRequest request = (FtpWebRequest)WebRequest.Create(URI);
            //提供身份验证信息
            request.Credentials = new NetworkCredential(UserName, Password);
            //设置请求完成之后是否保持到FTP服务器的控制连接，默认值为true
            request.KeepAlive = false;
            return request;
        }

        private bool _CreateDirectory(string ftpDirPath)
        {
            try
            {
                FtpWebRequest request = _GetRequest(ftpDirPath);
                request.Method = WebRequestMethods.Ftp.MakeDirectory;
                FtpWebResponse response = (FtpWebResponse)request.GetResponse();
                return true;
            }
            catch (Exception ex)
            {
                Logger.Default.Warn("FTP 服务器创建文件夹失败，文件夹路径：" + ftpDirPath, ex);
                throw ex;
            }
        }

        private bool _DirectoryExists(string ftpDirPath)
        {
            try
            {
                FtpWebRequest request = _GetRequest(ftpDirPath);
                request.Method = WebRequestMethods.Ftp.ListDirectory;
                FtpWebResponse response = (FtpWebResponse)request.GetResponse();
                return true;
            }
            catch (Exception ex)
            {
                Logger.Default.Warn("FTP 服务器上没有该文件夹，文件夹地址：" + ftpDirPath, ex);
                return false;
            }
        }

        private bool _FileExists(string ftpFilePath)
        {
            try
            {
                var request = _GetRequest(ftpFilePath);
                request.Method = WebRequestMethods.Ftp.GetDateTimestamp;
                FtpWebResponse response = (FtpWebResponse)request.GetResponse();
                return true;
            }
            catch (Exception ex)
            {
                Logger.Default.Warn("FTP 服务器上没有该文件，文件地址：" + ftpFilePath, ex);
                throw ex;
            }
        }

        private bool _FileDelete(string ftpFilePath)
        {
            try
            {
                var request = _GetRequest(ftpFilePath);
                request.Method = WebRequestMethods.Ftp.DeleteFile;
                FtpWebResponse response = (FtpWebResponse)request.GetResponse();
                return true;
            }
            catch (Exception ex)
            {
                Logger.Default.Warn("FTP 服务器删除失败，文件地址：" + ftpFilePath, ex);
                throw ex;
            }
        }
    }
}
